package ro.qi.framework.sys.i18n.locales;

import java.util.Calendar;
import java.util.Enumeration;
import java.util.Hashtable;

import ro.qi.framework.sys.debug.Logger;
import ro.qi.framework.sys.i18n.locales.entities.Locale;
import ro.qi.framework.sys.i18n.locales.entities.LocaleCollection;

public class LocalesManager {

	private static Hashtable localesCachedById = new Hashtable();
	private static Hashtable localesCachedByCode = new Hashtable();

	private static LocaleCollection locales = null;
	private static Locale defaultLocale = null;

	private static LocalesManager instance = null;

	private LocalesManager() {
	}

	public void init() {
		localesCachedById = new Hashtable();
		localesCachedByCode = new Hashtable();
		cacheLocales();
	}

	public static synchronized LocalesManager getInstance() {
		if (instance == null) {
			instance = new LocalesManager();
			instance.init();
		}
		return instance;
	}

	public void stop() {
		localesCachedById.clear();
		localesCachedByCode.clear();
		localesCachedById = null;
		localesCachedByCode = null;
		instance = null;
	}

	public static boolean isStarted() {
		return instance != null;
	}

	/*
	 * 
	 */
	public void initCache() {
		
	}

	/*
	 * 
	 */
	public void refreshCache() {
		cacheLocales();
	}

	public String getCache() {
		StringBuffer stringBuffer = new StringBuffer();
		
		stringBuffer.append("<p>localesCachedById:</p>");
		Enumeration enum1 = localesCachedById.keys ();
		while (enum1.hasMoreElements ()) {
			Integer key = (Integer) enum1.nextElement ();
			Locale value = (Locale) localesCachedById.get(key);
			stringBuffer.append(key + ": " + value.getId() + "<br>");
		}
		stringBuffer.append("<p>localesCachedByCode:</p>");
		Enumeration enum2 = localesCachedByCode.keys ();
		while (enum2.hasMoreElements ()) {
			String key = (String) enum2.nextElement ();
			Locale value = (Locale) localesCachedByCode.get(key);
			stringBuffer.append(key + ": " + value.getId() + "<br>");
		}
		
		return stringBuffer.toString();
	}

	public void getHashtableContent(Hashtable hashtable) {
		Enumeration enum1 = hashtable.keys ();
		while (enum1.hasMoreElements ()) {
			String key = (String) enum1.nextElement ();
			Integer value = (Integer) hashtable.get (key);
			System.out.println ("{ " + key + ", " + value + " }");
		}
	} 
	/*
	 * 
	 */
	public void cacheLocales() {

		Logger.info(this, "Start caching locales");

		Calendar startTime = Calendar.getInstance();

		// retrieve locales
		locales = new LocaleCollection();

		for (int idx = 0; idx < locales.getCollectionSize(); idx++) {
			Locale locale = locales.getLocale(idx);

			if (locale.isPublished()) {
				Logger.info(this, "Locale: " + locale.getName() + " (" + locale.getCode() + " - " + locale.getId() + ") cached.");

//				localesIds.add(idx, new Integer(locale.getId()));
				localesCachedById.put(new Integer(locale.getId()), locale);
				localesCachedByCode.put(locale.getCode(), locale);
			
				if (idx == 0) {
					defaultLocale = new Locale(locale.getId());
				}
			} else {
				Logger.info(this, "Locale: " + locale.getName() + " (" + locale.getCode() + " - " + locale.getId() + ") was not cached because is not published.");
				
			}
		}

		if (defaultLocale == null) {
			// set another default locale
//			LocaleCollection tmpLocales = new LocaleCollection();
//			if (tmpLocales.getCollectionSize() > 0) {
//				Locale locale = new Locale();
//				locale.setId(tmpLocales.getLocaleId(0));
//				locale.setLanguage(tmpLocales.getLocaleLanguage(0));
//				locale.setCountry(tmpLocales.getLocaleCountry(0));
//				locale.setVariant(tmpLocales.getLocaleVariant(0));
//				locale.setPriority(tmpLocales.getLocalePriority(0));
//				defaultLocale = locale;
//			} else {
				defaultLocale = new Locale();
//			}
		}

		Logger.info(this, "Default locale: " + defaultLocale.getName() + " (" + defaultLocale.getCode() + " - " + defaultLocale.getId() + ")");

		Calendar endTime = Calendar.getInstance();
		double diff = endTime.getTime().getTime() - startTime.getTime().getTime();

		Logger.info(this, "End caching locales (" + diff + " ms)");
		Logger.info(this, "Readed:\t" + locales.getCollectionSize() + " locales");
	}

	/**
	 *	getLocale by id
	 * 
	 */
	public Locale getLocale(int localeId) { // throws LocalesException {
		if (localesCachedById.containsKey(new Integer(localeId)) ) {
			return (Locale)localesCachedById.get(new Integer(localeId));
		} else {
			Logger.warning(this, "Locale id \"" + localeId + "\" not found in cache.");
//			throw new LocalesExceptionLocaleNotFound();
			return new Locale();
		}
	}

	/**
	 *	getLocale by code 
	 * 
	 */
	public Locale getLocale(String localeCode) { // throws LocalesException {
		if (localesCachedByCode.containsKey(localeCode)) {
			return (Locale)localesCachedByCode.get(localeCode);
		} else {
//			CallDetective cd = new CallDetective();
//			System.out.println("caller 0: " + cd.findCaller(0));
//			System.out.println("caller 1: " + cd.findCaller(1));
//			System.out.println("caller 2: " + cd.findCaller(2));
//			System.out.println("caller 3: " + cd.findCaller(3));
//			System.out.println("caller 4: " + cd.findCaller(4));
//			System.out.println("caller 5: " + cd.findCaller(5));
//			System.out.println("caller 6: " + cd.findCaller(6));
//			System.out.println("caller 7: " + cd.findCaller(7));
//			Logger.warning(this, "Locale code \"" + localeCode + "\" not found in cache.");
//			throw new LocalesExceptionLocaleNotFound();
			return new Locale();
		}

	}

	public Locale getDefaultLocale() {

		if (defaultLocale == null) {
			// no locales defined
			Logger.error(this, "No locales defined on this system or no database connection.");
			return new Locale();
		}

		return defaultLocale;
	}

	public LocaleCollection getCollection() {
		return locales;
	}

	public int getCollectionSize() {
		return localesCachedById.size();
	}

	public int getId(int index) {
		return getLocale(locales.getId(index)).getId();
	}

//	public Locale getLocale(int index) {
//		return getLocale(locales.getId(index));
//	}

	/**
	 * Try to get rid of the code below
	 * 
	 */
//	public String getLanguage(int index) {
//		return getLocale(locales.getId(index)).getLanguage();
//	}
//
//	public String getCountry(int index) {
//		return getLocale(locales.getId(index)).getCountry();
//	}
//
//	public String getVariant(int index) {
//		return getLocale(locales.getId(index)).getVariant();
//	}
//
//	public String getCode(int index) {
//		return getLocale(locales.getId(index)).getCode();
//	}
//
//	public String getName(int index) {
//		return getLocale(locales.getId(index)).getName();
//	}

//	private static Vector localesIds = new Vector();

//	private void refreshLocale(String localeName, String localeCaller) {
//		Locale locale = new Locale(localeName);
//		if( locale.getId() == 0 ) {
//			Logger.error(this, "(" + localeCaller + ") Locale with name " + localeName + " not found in database");
//			return;
//		}
//		locales.put( locale.getName(), locale);
//		localesIds.put( new Integer(locale.getId()), locale.getName());
//	}
//
//	private void refreshLocale(int localeId) {
//		Locale locale = new Locale(localeId);
//		if (locale.getId() == 0)
//			return;
//		locales.put(locale.getName(), locale);
//		localesIds.put(new Integer(locale.getId()), locale.getName());
//	}
//
//	public String getLocale(String localeName, String localeLanguage, String localeCountry, String localeVariant, String localeCaller) {
//		return getLocale(localeName, LocaleCollection.getLocaleIdByLanguage(localeLanguage), localeCaller);
//	}
//
//	public void checkForUpdates() {
//		lastUpdate = new Date();
//
//		try {
//			// checks if there are any locales updated
//			if (localesIds != null && localesIds.size() > 0) {
//				LocaleCollection localeCollection = new LocaleCollection();
//				if (localeCollection != null) {
//
//					for( int i = 0 ; i < localeCollection.getCollectionSize() ; i++ ) {
//
//						Integer resId = new Integer(localeCollection.getLocaleId(i));
//
//						if (localesIds.containsKey(resId) ) {
//							String localeName = (String)localesIds.get(resId);
//							Locale locale = (Locale)locales.get(localeName);
//
//							if (locale != null) {
//								
//								Logger.debug(this, "Locale " + localeName + " was modified: " + DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL, Locale.ENGLISH).format(res.getLocaleUpdateTime(i)));
//								refreshLocale(localeCollection.getLocaleId(i));
//							}
//						}
//					}
//				}
//			}
//		} catch (Throwable t) {
//			t.printStackTrace();
//		}
//	}
//
//	public static Locale getDefaultLocaleId() {
//
//		if (defaultLocale == null) {
//			LocaleCollection tmpLocales = new LocaleCollection();
//			if (tmpLocales.getCollectionSize() > 0) {
//				Locale locale = new Locale();
//				locale.setId(tmpLocales.getLocaleId(0));
//				locale.setLanguage(tmpLocales.getLocaleLanguage(0));
//				locale.setCountry(tmpLocales.getLocaleCountry(0));
//				locale.setVariant(tmpLocales.getLocaleVariant(0));
//				locale.setPriority(tmpLocales.getLocalePriority(0));
//				defaultLocale = locale;
//			} else {
//				// no locales defined
//				Logger.error("Locales.getDefaultLocaleId(): No locales defined on this system or no database connection.");
//				return new Locale();
//			}
//		}
//
//		return defaultLocale;
//	}
//
//	public static Locale getLocaleById(int localeId) {
//		Integer id = new Integer(localeId);
//		if (locales.containsKey(id)) {
//			return (Locale)locales.get(id);
//		}
//		LocaleCollection tmpLocales = new LocaleCollection();
//		for (int i = 0 ; i < tmpLocales.getCollectionSize() ; i++) {
//			if (tmpLocales.getLocaleId(i) == localeId){
//				Locale locale = new Locale();
//				locale.setId(tmpLocales.getLocaleId(i));
//				locale.setLanguage(tmpLocales.getLocaleLanguage(i));
//				locale.setCountry(tmpLocales.getLocaleCountry(i));
//				locale.setVariant(tmpLocales.getLocaleVariant(i));
//				locale.setPriority(tmpLocales.getLocalePriority(i));
//				locales.put(id, locale);
//				return locale; 
//			}
//		}
//		return new Locale();
//	}
//
//	public static int getLocaleIdByLanguage(String language) {
//		if (langIds.containsKey(language)) {
//			return ((Integer)langIds.get(language)).intValue();
//		}
//		LocaleCollection locales = new LocaleCollection();
//		for( int i = 0 ; i < locales.getCollectionSize() ; i++ ) {
//			if( locales.getLocaleLanguage(i).toUpperCase().equals( language.toUpperCase() )){
//				langIds.put(language, new Integer(locales.getLocaleId(i)));
//				return locales.getLocaleId(i); 
//			}
//		}
//		return 0;
//	}
//
//	public String getLocaleCode(int index) {
//		if (index < getCollectionSize()) {
//			StringBuffer name = new StringBuffer();
//			String language = getLocaleLanguage(index);
//			String country = getLocaleCountry(index);
//			String variant = getLocaleVariant(index);
//			if( language != null && language.length() > 0 ) {
//				name.append(language);
//			} else {
//				name.append("*");
//			}
//			if( country != null && country.length() > 0 ) {
//				if( name.length() == 0 ) {
//					name.append("*.");
//				} else {
//					name.append(".");
//				}
//				name.append(country);
//			}
//			if( variant != null && variant.length() > 0 ) {
//				if( name.length() == 0 ) {
//					name.append("*.*.");
//				} else {
//					name.append(".");
//				}
//				name.append(variant);
//			}
//			return name.toString().toUpperCase();
//		}
//		return "";
//	}

}
